#include "audio_encoder.h"
esp_audio_enc_handle_t encoder = NULL;

my_encoder_t my_encoder;
void audio_encoder_init(void)
{

    esp_opus_enc_config_t opus_cfg = {
        .sample_rate = 16000,
        .channel = 1,
        .bits_per_sample = 16,
        .bitrate = 32000,
        .frame_duration = ESP_OPUS_ENC_FRAME_DURATION_60_MS,
        .application_mode = ESP_OPUS_ENC_APPLICATION_AUDIO,
        .complexity = 5,
        .enable_fec = false,
        .enable_dtx = false,
        .enable_vbr = false};
    esp_opus_enc_open(&opus_cfg, sizeof(esp_opus_enc_config_t), &encoder);
}

void encoder_task(void *args);
void audio_encoder_start(RingbufHandle_t inputBuf, RingbufHandle_t outputBuf)
{

    my_encoder.is_running = true;
    my_encoder.inputBuf = inputBuf;
    my_encoder.outputBuf = outputBuf;

    xTaskCreatePinnedToCoreWithCaps(&encoder_task, "encoder_task", 64 * 1024, NULL, 5, NULL, 1, MALLOC_CAP_SPIRAM);
}

void copy_from_ringbuf(RingbufHandle_t ringBuf,
                       uint8_t *to_buffer,
                       int size)
{

    while (size > 0)
    {
        size_t item_size = 0;
        uint8_t *data = xRingbufferReceiveUpTo(ringBuf, &item_size, portMAX_DELAY, size);
        memcpy(to_buffer, data, item_size);
        size -= item_size;
        to_buffer += item_size;
        vRingbufferReturnItem(ringBuf, data); // 归还缓冲区
    }
}

void encoder_task(void *args)
{

    int pcm_size = 0, raw_size = 0;
    // 获取输入帧输出帧的大小
    //  向编码器询问：“编码一帧数据，我需要喂给你多少PCM数据（pcm_size）？你一次会吐出多少字节的编码数据（raw_size）
    esp_opus_enc_get_frame_size(encoder, &pcm_size, &raw_size);

    // 编码器是以“帧”为单位工作的。它一次吃进去一帧PCM，吐出来一帧OPUS
    uint8_t *pcm_data = heap_caps_malloc(pcm_size, MALLOC_CAP_SPIRAM);
    uint8_t *raw_data = heap_caps_malloc(raw_size, MALLOC_CAP_SPIRAM);

    // 存放要编码的数据
    esp_audio_enc_in_frame_t in_frame = {
        .buffer = pcm_data,
        .len = pcm_size,
    };

    // 存放编码后的数据
    esp_audio_enc_out_frame_t out_frame = {
        .buffer = raw_data,
        .len = raw_size,
    };

    while (my_encoder.is_running)
    {
        // size_t item_size = xRingbufferReceive(my_encoder.inputBuf, (void **)&in_frame.buffer, portMAX_DELAY);
        copy_from_ringbuf(my_encoder.inputBuf, in_frame.buffer, in_frame.len);
        esp_opus_enc_process(encoder, &in_frame, &out_frame);
        // todo  可能这里有错
        xRingbufferSend(my_encoder.outputBuf, out_frame.buffer, out_frame.encoded_bytes, portMAX_DELAY);
    }

    free(pcm_data);
    free(raw_data);
    esp_opus_enc_close(encoder);
    vTaskDelete(NULL);
}